#include "ch32v_def.h"
#include "PinNames.h"
#include "analog.h"
#include "pinmap.h"

#ifndef ADC_SAMPLINGTIME
#if defined(ADC_SampleTime_8Cycles5)
#define ADC_SAMPLINGTIME ADC_SampleTime_8Cycles5
#endif
#if defined(ADC_SampleTime_12Cycles5)
#define ADC_SAMPLINGTIME ADC_SampleTime_12Cycles5
#endif
#if defined(ADC_SampleTime_13Cycles5)
#define ADC_SAMPLINGTIME ADC_SampleTime_13Cycles5
#endif
#if defined(ADC_SampleTime_15Cycles)
#define ADC_SAMPLINGTIME ADC_SampleTime_15Cycles
#endif
#if defined(ADC_SampleTime_16Cycles)
#define ADC_SAMPLINGTIME ADC_SampleTime_16Cycles
#endif
#if defined(ADC_SampleTime_19Cycles5)
#define ADC_SAMPLINGTIME ADC_SampleTime_19Cycles5
#endif
#endif

#ifndef ADC_SAMPLINGTIME_INTERNAL
#if defined(ADC_SampleTime_480Cycles)
#define ADC_SAMPLINGTIME_INTERNAL ADC_SampleTime_480Cycles
#endif
#if defined(ADC_SampleTime_384Cycles)
#define ADC_SAMPLINGTIME_INTERNAL ADC_SampleTime_384Cycles
#endif
#if defined(ADC_SampleTime_810Cycles5)
#define ADC_SAMPLINGTIME_INTERNAL ADC_SampleTime_810Cycles5
#endif
#if defined(ADC_SampleTime_640Cycles5)
#define ADC_SAMPLINGTIME_INTERNAL ADC_SampleTime_640Cycles5
#endif
#if defined(ADC_SampleTime_601Cycles5)
#define ADC_SAMPLINGTIME_INTERNAL ADC_SampleTime_601Cycles5
#endif
#if defined(ADC_SampleTime_247Cycles5)
#define ADC_SAMPLINGTIME_INTERNAL ADC_SampleTime_247Cycles5
#endif
#if defined(ADC_SampleTime_239Cycles5)
#define ADC_SAMPLINGTIME_INTERNAL ADC_SampleTime_239Cycles5
#endif
#if defined(ADC_SampleTime_160Cycles5)
#define ADC_SAMPLINGTIME_INTERNAL ADC_SampleTime_106Cycles5
#endif
#endif

static inline uint32_t get_adc_channel(PinName pin)
{
    uint32_t function = pinmap_function(pin, PinMap_ADC);
    uint32_t channel = 0;

    switch (STM_PIN_CHANNEL(function))
    {
    case 0:
        channel = ADC_Channel_0;
        break;
    case 1:
        channel = ADC_Channel_1;
        break;
    case 2:
        channel = ADC_Channel_2;
        break;
    case 3:
        channel = ADC_Channel_3;
        break;
    case 4:
        channel = ADC_Channel_4;
        break;
    case 5:
        channel = ADC_Channel_5;
        break;
    case 6:
        channel = ADC_Channel_6;
        break;
    case 7:
        channel = ADC_Channel_7;
        break;
    case 8:
        channel = ADC_Channel_8;
        break;
    case 9:
        channel = ADC_Channel_9;
        break;
#ifdef ADC_Channel_10
    case 10:
        channel = ADC_Channel_10;
        break;
#endif
#ifdef ADC_Channel_11
    case 11:
        channel = ADC_Channel_11;
        break;
#endif
#ifdef ADC_Channel_12
    case 12:
        channel = ADC_Channel_12;
        break;
#endif
#ifdef ADC_Channel_13
    case 13:
        channel = ADC_Channel_13;
        break;
#endif
#ifdef ADC_Channel_14
    case 14:
        channel = ADC_Channel_14;
        break;
#endif
#ifdef ADC_Channel_15
    case 15:
        channel = ADC_Channel_15;
        break;
#endif
#ifdef ADC_Channel_16
    case 16:
        channel = ADC_Channel_16;
        break;
#endif
#ifdef ADC_Channel_17
    case 17:
        channel = ADC_Channel_17;
        break;
#endif
    default:
        channel = 0;
        break;
    }

    return channel;
}

static inline uint32_t get_adc_internal_channel(PinName pin)
{
    uint32_t channel = 0;
    switch (pin)
    {
#ifdef ADC_Channel_TempSensor
    case PADC_TEMP:
        channel = ADC_Channel_TempSensor;
        break;
#endif
#ifdef ADC_Channel_Vrefint
    case PADC_VREF:
        channel = ADC_Channel_Vrefint;
        break;
#endif
    default:
        _Error_Handler("ADC: Unknown adc internal PiName", (int)(pin));
        break;
    }
    return channel;
}

static inline void enableADCClock(ADC_TypeDef *instance)
{
    switch ((uint32_t)instance)
    {
    case ADC1_BASE:
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
        break;
#ifdef ADC2_BASE
    case ADC2_BASE:
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
        break;
#endif
#if defined(ADC3_BASE) && defined(RCC_APB2Periph_ADC3) 
    case ADC3_BASE:
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
        break;
#endif
    }
}

uint16_t adc_read_value(PinName pin, uint32_t resolution)
{
    ADC_InitTypeDef ADC_InitStructure;
    uint32_t channel = 0;
    ADC_TypeDef *instance = NP;
    uint32_t samplingTime = ADC_SAMPLINGTIME;

    if ((pin & PADC_BASE) && (pin < ANA_START))
    {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        instance = ADC1;
        channel = get_adc_internal_channel(pin);
        samplingTime = ADC_SAMPLINGTIME_INTERNAL;
    }
    else
    {
        instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC);
        channel = get_adc_channel(pin);
    }

    if (instance == NP)
        return 0;
    enableADCClock(instance);

    RCC_ADCCLKConfig(RCC_PCLK2_Div8); // 设置ADC时钟分频为8分频

    ADC_DeInit(instance);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                  // 配置ADC为独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;                       // 设置在单通道模式下执行转换
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                 // 设置在单次模式下执行转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 设置转换不是由外部触发启动
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              // 设置ADC数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;                             // 顺序进行规则转换的ADC通道的数目
    ADC_Init(instance, &ADC_InitStructure);                             // 根据ADC_InitStructure中指定的参数初始化ADC寄存器

    if ((pin & PADC_BASE) && (pin < ANA_START))
    {
        ADC_TempSensorVrefintCmd(ENABLE);
    }
    else
    {
        ADC_TempSensorVrefintCmd(DISABLE);
    }
    ADC_Cmd(instance, ENABLE); // 使能ADC1

    ADC_ResetCalibration(instance); // 重置ADC1校准寄存器。
    while (ADC_GetResetCalibrationStatus(instance))
        ; // 等待复位校准结束

    ADC_StartCalibration(instance); // 开启AD校准
    while (ADC_GetCalibrationStatus(instance))
        ; // 等待校准结束

    ADC_ClearFlag(instance, ADC_FLAG_EOC);                        // 清除完成转换标志
    ADC_RegularChannelConfig(instance, channel, 1, samplingTime); // 为所选ADC常规通道配置其在序列器中的相应列组及其采样时间。
    ADC_SoftwareStartConvCmd(instance, ENABLE);                   // 使能ADC1软件启动转换

    while (!ADC_GetFlagStatus(instance, ADC_FLAG_EOC))
        ; // 等待转换结束

    return ADC_GetConversionValue(instance); // 返回常规通道的最后一个ADC1转换结果数据
}

void pwm_start(PinName pin, uint32_t clock_freq, uint32_t value, TimerCompareFormat_t resolution)
{
    TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin, PinMap_PWM);

    HardwareTimer *HT;
    TimerModes_t previousMode;
    uint32_t index = get_timer_index(Instance);

    if (HardwareTimer_Handle[index] == NULL)
    {
        HardwareTimer_Handle[index]->__this = new HardwareTimer(Instance);
    }

    HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this);

    uint32_t channel = STM_PIN_CHANNEL(pinmap_function(pin, PinMap_PWM));

    previousMode = HT->getMode(channel);
    if (previousMode != TIMER_OUTPUT_COMPARE_PWM1)
    {
        HT->setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
    }
    HT->setOverflow(clock_freq, HERTZ_FORMAT);
    HT->setCaptureCompare(channel, value, resolution);
    if (previousMode != TIMER_OUTPUT_COMPARE_PWM1)
    {
        HT->resume();
    }
}

void pwm_stop(PinName pin)
{
    TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin, PinMap_PWM);
    HardwareTimer *HT;
    uint32_t index = get_timer_index(Instance);
    if (HardwareTimer_Handle[index] != NULL)
    {
        HT = (HardwareTimer *)(HardwareTimer_Handle[index]->__this);
        if (HT != NULL)
        {
            delete (HT);
            HT = NULL;
        }
    }
}

uint32_t get_pwm_channel(PinName pin)
{
    uint32_t function = pinmap_function(pin, PinMap_PWM);
    uint32_t channel = 0;
    switch (STM_PIN_CHANNEL(function))
    {
    case 1:
        channel = TIM_Channel_1;
        break;
    case 2:
        channel = TIM_Channel_2;
        break;
    case 3:
        channel = TIM_Channel_3;
        break;
    case 4:
        channel = TIM_Channel_4;
        break;
    default:
        break;
    }
    return channel;
}